import './styles.css';

export function createDiv(...clzs: string[]) {
    const div = document.createElement('div');
    div.classList.add(...clzs);
    return div;
}

export function createLabel(text: string, clzs: string[]) {
    const label = document.createElement('label');
    label.classList.add(...clzs);
    label.innerText = text;
    return label;
}


export class MoveableEle {

    protected window: HTMLDivElement;

    constructor(...clzs: string[]) {
        this.window = createDiv(...clzs);
    }

    protected appendChild(node: HTMLElement) {
        this.window.appendChild(node);
    }

    protected show() {
        document.addEventListener('mouseup', this.mouseUp);
        this.window.addEventListener('mousedown', this.mouseDown);
        document.addEventListener('mousemove', this.mouseMove);
        document.body.appendChild(this.window);
    }

    protected close() {
        document.body.removeChild(this.window);
        document.removeEventListener('mouseup', this.mouseUp);
        this.window.removeEventListener('mousedown', this.mouseDown);
        document.removeEventListener('mousemove', this.mouseMove);
    }

    private dragFlag = false;
    private offsetX = 0;
    private offsetY = 0;

    private mouseDown = this.onMouseDown.bind(this);
    private mouseMove = this.onMouseMove.bind(this);
    private mouseUp = this.onMouseUp.bind(this);

    private onMouseDown(e: MouseEvent) {
        this.dragFlag = true;
        const rect = this.window.getBoundingClientRect();
        this.offsetX = e.clientX - (rect.left + rect.width / 2);
        this.offsetY = e.clientY - (rect.top + rect.height / 2);
    }

    private onMouseMove(e: MouseEvent) {
        if (!this.dragFlag) {
            return;
        }
        const x = e.clientX - this.offsetX;
        const y = e.clientY - this.offsetY;
        this.window.style.left = `${x}px`;
        this.window.style.top = `${y}px`;
    }

    private onMouseUp(_: MouseEvent) {
        this.dragFlag = false;
    }
}

export class Dialog extends MoveableEle {

    private titleLabel: HTMLLabelElement;
    private msgLabel: HTMLLabelElement;
    private iconDiv: HTMLDivElement;
    private closeDiv: HTMLDivElement;

    constructor(title: string, msg: string) {
        super('dialog', 'p10', 'flex_col', 'show_anim')

        this.titleLabel = createLabel(title, []);
        this.msgLabel = createLabel(msg, ['ml5']);
        this.iconDiv = createDiv('dialog_icon_prog');
        this.closeDiv = createDiv('dialog_btn_close', 'dialog_space');
        this.closeDiv.onclick = () => { this.close(); }

        let row = createDiv('flex_row_center', 'dialog_title_row');
        row.appendChild(createDiv('dialog_space'));
        row.appendChild(this.titleLabel);
        row.appendChild(this.closeDiv);
        this.appendChild(row);

        row = createDiv('flex_row_center', 'mt5');
        row.appendChild(this.iconDiv);
        row.appendChild(this.msgLabel);
        this.appendChild(row);

        this.show();
    }

    setMsg(msg: string) {
        this.msgLabel.innerText = msg;
    }

    close() {
        this.window.classList.remove('show_anim');
        const _n = this.window.offsetHeight;
        this.window.classList.add('close_anim');
        this.window.addEventListener('animationend', () => {
            super.close();
        })
    }

    success(msg: string) {
        this.iconDiv.classList.remove(...this.iconDiv.classList);
        this.iconDiv.classList.add('dialog_icon_succ');
        this.msgLabel.innerText = msg;
    }

    error(msg: string) {
        this.iconDiv.classList.remove(...this.iconDiv.classList);
        this.iconDiv.classList.add('dialog_icon_err');
        this.msgLabel.innerText = msg;
    }

    alm(msg: string) {
        this.iconDiv.classList.remove(...this.iconDiv.classList);
        this.iconDiv.classList.add('dialog_icon_alm');
        this.msgLabel.innerText = msg;
    }
}

export async function delay(ms: number) {
    return new Promise((resolve, _) => {
        setTimeout(resolve, ms);
    })
}

export async function runAction2(title: string, msg: string, cb: (dialog: Dialog) => Promise<void>) {
    const dialog = new Dialog(title, msg);
    try {
        await cb(dialog);
        dialog.close();
    } catch (e) {
        dialog.error(e as string);
    }
}

export async function runAction(title: string, msg: string, cb: (dialog: Dialog) => Promise<void>) {
    const dialog = new Dialog(title, msg);
    try {
        await cb(dialog);
        dialog.success(`${msg}执行成功`);
        await delay(500);
        dialog.close();
    } catch (e) {
        dialog.error(e as string);
    }
}

export async function run(cb: () => Promise<void>) {
    try {
        await cb();
    } catch (e) {
        const dialog = new Dialog('错误', '');
        dialog.error(e as string);
    }
}

export async function runAction3(title: string, msg: string, cb: (dialog: Dialog) => Promise<string>) {
    const dialog = new Dialog(title, msg);
    try {
        const ret = await cb(dialog);
        dialog.success(`${ret}`);
    } catch (e) {
        dialog.error(e as string);
    }
}
